﻿using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Sgr.Data;
using Sgr.EntityFrameworkCore;
using System.Reflection;

namespace Sgr.Admin.WebHost.Infrastructure.Factories
{
    /**
    *
    * 使用说明
    *
    * 1. vs 使用
    *  - 安装工具命令：dotnet tool install --global dotnet-ef
    *  - 更新工具命令：dotnet tool update --global dotnet-ef
    *  - 验证工具安装情况：dotnet ef --version
    *
    * 2. 迁移命令
    *
    *  - 添加迁移 dotnet ef migrations add SgrSchemaSchema --context SgrDbContext --output-dir Infrastructure/Migrations/Sgr
    *  - 删除迁移 dotnet ef migrations remove --context SgrDbContext
    *
    * 3. 数据库命令
    *
    * - 更新数据库 dotnet ef database update --context SgrDbContext
    * - 删除数据库 dotnet ef database drop --context SgrDbContext （使用的时候一定要注意）
    *
    * 4. SQL脚本
    * - 生成整个数据库的SQL脚本 dotnet ef migrations script --context SgrDbContext --output ../../../docs/sql/sgrdb.sql
    * - 生成幂等SQL脚本 dotnet ef migrations script --idempotent --context SgrDbContext --output ../../../docs/sql/idempotent_sgrdb.sql
    *
    * 其它
    * - 如果命令行工具输出乱码，可使用：$OutputEncoding = [Console]::OutputEncoding = [System.Text.Encoding]::UTF8
    * - 如果命令行工作目录不对，可使用：cd src/Apps/Sgr.Admin.WebHost
    * - 检查命令行工作目录：$pwd
    */

    /// <summary>
    /// Sgr数据库上下文设计时工厂
    /// </summary>
    public class SgrDbContextDesignFactory : IDesignTimeDbContextFactory<SgrDbContext>
    {
        /// <summary>
        ///
        /// </summary>
        /// <param name="args"></param>
        /// <returns></returns>
        public SgrDbContext CreateDbContext(string[] args)
        {
            //System.Diagnostics.Debugger.Launch();

            // 1. 加载配置
            var config = new ConfigurationBuilder()
               .SetBasePath(Directory.GetCurrentDirectory())
               .AddJsonFile("appsettings.json", optional: true)
               .AddJsonFile("Config/sgr_database.json", optional: false, reloadOnChange: true)
               .AddEnvironmentVariables()
               .Build();

            // 2. 扫描并注册所有模块的Entity配置
            var providers = RegisterModuleEntityTypes();

            // 3. 获取数据库配置
            var connections = config.GetSection("Sgr:DataConnectionStrings").Get<List<DataConnectionString>>() ?? throw new InvalidOperationException("未找到数据库连接配置 Sgr:DataConnectionStrings");
            var dbConnection = connections?.FirstOrDefault(f => f.Name == Constant.DEFAULT_DATABASE_SOURCE_NAME)
                ?? throw new InvalidOperationException("未找到有效的数据库配置");

            // 4. 配置DbContext选项
            var optionsBuilder = new DbContextOptionsBuilder<SgrDbContext>();
            ConfigureDbContext(optionsBuilder, dbConnection);

            // 5. 创建DbContext实例
            return new SgrDbContext(optionsBuilder.Options, providers);
        }

        /// <summary>
        /// 扫描当前应用程序输出目录中的所有程序集，查找并实例化 IEntityFrameworkTypeProvider 的实现。
        /// 适用于 EF Core 设计时（如 dotnet ef migrations）和运行时。
        /// </summary>
        private static List<IEntityFrameworkTypeProvider> RegisterModuleEntityTypes()
        {
            var result = new List<IEntityFrameworkTypeProvider>();
            var loadedAssemblyNames = new HashSet<string>();

            string baseDirectory = AppContext.BaseDirectory;
            string[] dllFiles = Directory.GetFiles(baseDirectory, "*.dll");

            foreach (string dllPath in dllFiles)
            {
                try
                {
                    // 仅读取程序集元数据，不加载到内存
                    AssemblyName assemblyName = AssemblyName.GetAssemblyName(dllPath);

                    // 避免重复处理同一程序集（按 FullName 去重）
                    if (!loadedAssemblyNames.Add(assemblyName.FullName))
                        continue;

                    // 跳过 .NET 系统程序集（可选但推荐）
                    string simpleName = assemblyName.Name ?? string.Empty;
                    //if (simpleName.StartsWith("System.", StringComparison.OrdinalIgnoreCase) ||
                    //    simpleName.StartsWith("Microsoft.", StringComparison.OrdinalIgnoreCase) ||
                    //    simpleName.Equals("netstandard", StringComparison.OrdinalIgnoreCase) ||
                    //    simpleName.Equals("mscorlib", StringComparison.OrdinalIgnoreCase))
                    //{
                    //    continue;
                    //}
                    if (!simpleName.StartsWith("Sgr.", StringComparison.OrdinalIgnoreCase))
                        continue;

                    // 正式加载程序集（由 .NET 标准加载机制处理，避免上下文问题）
                    Assembly assembly = Assembly.Load(assemblyName);

                    // 获取所有类型（容忍部分类型加载失败）
                    Type[] types;
                    try
                    {
                        types = assembly.GetTypes();
                    }
                    catch (ReflectionTypeLoadException ex)
                    {
                        Console.WriteLine($"警告：加载程序集 '{dllPath}' 的类型时部分失败: {ex.Message}");
                        continue;
                    }

                    // 查找所有非抽象、实现 IEntityFrameworkTypeProvider 的类
                    var providerTypes = types
                        .Where(t => t.IsClass && !t.IsAbstract && typeof(IEntityFrameworkTypeProvider).IsAssignableFrom(t));

                    foreach (Type providerType in providerTypes)
                    {
                        try
                        {
                            if (Activator.CreateInstance(providerType) is IEntityFrameworkTypeProvider instance)
                            {
                                result.Add(instance);
                            }
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine($"警告：无法创建实体配置提供器实例 '{providerType.FullName}'。原因: {ex.Message}");
                        }
                    }
                }
                catch (BadImageFormatException)
                {
                    // 跳过非托管 DLL 或架构不匹配的文件（如 .winmd、native DLL）
                    continue;
                }
                catch (FileLoadException ex)
                {
                    Console.WriteLine($"警告：无法加载程序集 '{dllPath}'。原因: {ex.Message}");
                    continue;
                }
                catch (FileNotFoundException ex)
                {
                    // 程序集存在但依赖缺失（常见于设计时）
                    Console.WriteLine($"警告：程序集 '{dllPath}' 所需依赖未找到。原因: {ex.Message}");
                    continue;
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"错误：处理程序集文件 '{dllPath}' 时发生未预期异常: {ex.Message}");
                    continue;
                }
            }

            return result;
        }

        /// <summary>
        /// 配置DbContext选项
        /// </summary>
        private static void ConfigureDbContext(DbContextOptionsBuilder optionsBuilder, DataConnectionString dbConnection)
        {
            switch (dbConnection.DbProvider)
            {
#if DB_MYSQL
                case DatabaseType.MySql:
                    optionsBuilder.UseMySql(
                        dbConnection.ConnectionString,
                        ServerVersion.AutoDetect(dbConnection.ConnectionString),
                        b =>
                        {
                            b.MigrationsAssembly("Sgr.Admin.WebHost");
                            // 指定SGR基础模块的迁移历史表
                            b.MigrationsHistoryTable("__EF_MigrationsHistory_SGR");
                        });
                    break;
#endif

#if DB_SQLITE
             case DatabaseType.SQLite:
                    optionsBuilder.UseSqlite(
                        dbConnection.ConnectionString,
                        b =>
                        {
                            b.MigrationsAssembly("Sgr.Admin.WebHost");
                            // 指定SGR基础模块的迁移历史表
                            b.MigrationsHistoryTable("__EF_MigrationsHistory_SGR");
                        });
                    break;
#endif

                default:
                    throw new InvalidOperationException($"不支持的数据库类型: {dbConnection.DbProvider}");
            }

            //if (Environment.IsProduction())
            //{
            //    // 禁用敏感信息日志和详细错误
            //    optionsBuilder
            //        .ConfigureWarnings(w => w.Log(RelationalEventId.CommandExecuting));
            //}

            //if (Environment.IsDevelopment())
            //{
            //    optionsBuilder
            //        .EnableSensitiveDataLogging()
            //        .EnableDetailedErrors();
            //}
        }
    }
}